package mobi.celton.treeshaker.builder;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Map;
import mobi.celton.treeshaker.Main;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;

public class Treeshaker extends IncrementalProjectBuilder
{
	public static final String BUILDER_ID = "mobi.celton.treeshaker.TreeshakerBuilder";

	private static final String MARKER_TYPE = "mobi.celton.treeshaker.treeshakerProblem";

	private void addMarker(String message, int lineNumber, int severity)
	{
		try
		{
			IMarker marker = getProject().createMarker(MARKER_TYPE);
			marker.setAttribute(IMarker.MESSAGE, message);
			marker.setAttribute(IMarker.SEVERITY, severity);
			if(lineNumber == -1)
			{
				lineNumber = 1;
			}
			marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
		}
		catch(CoreException e)
		{}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
	 * java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException
	{
		if(kind == FULL_BUILD)
		{
			fullBuild(monitor);
		}
		else
		{
			IResourceDelta delta = getDelta(getProject());
			if(delta == null)
			{
				fullBuild(monitor);
			}
			else
			{
				incrementalBuild(delta, monitor);
			}
		}
		return null;
	}

	private static IPath findScalaLibrary(IJavaProject prj)
	{
		try
		{
			final IClasspathEntry[] classPaths = prj.getResolvedClasspath(true);
			if(classPaths != null)
			{
				for(IClasspathEntry res: classPaths)
				{
					if(res.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
					{
						final IPath path = res.getPath();
						if(path.lastSegment().equals("scala-library.jar"))
							return path.makeAbsolute();
					}
				}
			}
			return null;
		}
		catch(CoreException e)
		{
			return null;
		}
	}
	
	private IPath getOutputLocation(IJavaProject javaProject) throws JavaModelException
	{
		final IWorkspaceRoot wsRoot = getProject().getWorkspace().getRoot();
		final IFolder outputFolder = wsRoot.getFolder(javaProject.getOutputLocation());
		return outputFolder.getRawLocation();
	}
	
	private IPath getWorkingLocation()
	{
		return getProject().getWorkingLocation(BUILDER_ID);
	}
	
	protected void fullBuild(final IProgressMonitor monitor) throws CoreException
	{
		final IJavaProject javaProject = JavaCore.create(getProject());
		
		final String scalaLibrary = findScalaLibrary(javaProject).toString();
		if(scalaLibrary == null)
		{
			addMarker("scala-library.jar not found. Make sure the Scala nature is added to the project.", -1, IMarker.SEVERITY_ERROR);
			return;
		}
		
		final String locationOutput = getOutputLocation(javaProject).toString();
		final String workingLocation = getWorkingLocation().toString();

		try
		{
			Main.treeshake(workingLocation, locationOutput, scalaLibrary);
		}
		catch(FileNotFoundException e)
		{
			addMarker("File not found. " + e.getMessage(), -1, IMarker.SEVERITY_ERROR);
		}
		catch(IOException e)
		{
			addMarker("I/O error. " + e.getMessage(), -1, IMarker.SEVERITY_ERROR);
			e.printStackTrace();
		}
	}

	protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException
	{
		fullBuild(monitor);
	}
}
